package com.linsen.gateway.initializer;

import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.linsen.core.common.constant.LinsenConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * 动态路由初始化类
 *
 * @author zhaoyong
 * @date 2023/3/9
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteInitializer {

    private final RouteDefinitionWriter routeDefinitionWriter;
    private final NacosConfigProperties nacosConfigProperties;

    @PostConstruct
    public void initRoute() {
        try {
            Properties properties = new Properties();
            properties.put(PropertyKeyConst.SERVER_ADDR, this.nacosConfigProperties.getServerAddr());
            properties.put(PropertyKeyConst.USERNAME, this.nacosConfigProperties.getUsername());
            properties.put(PropertyKeyConst.PASSWORD, this.nacosConfigProperties.getPassword());
            properties.put(PropertyKeyConst.NAMESPACE, this.nacosConfigProperties.getNamespace());
            ConfigService configService = NacosFactory.createConfigService(properties);

            String content = configService.getConfig(LinsenConstant.CONFIG_DATA_ID_DYNAMIC_ROUTES, this.nacosConfigProperties.getGroup(), LinsenConstant.CONFIG_TIMEOUT_MS);
            log.info("initializer gateway route begin");
            this.updateRoute(content);
            log.info("initializer gateway route complete");
            // 开启监听，实现动态
            configService.addListener(LinsenConstant.CONFIG_DATA_ID_DYNAMIC_ROUTES, this.nacosConfigProperties.getGroup(), new Listener() {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    log.info("update gateway route begin");
                    updateRoute(configInfo);
                    log.info("update gateway route complete");
                }

                @Override
                public Executor getExecutor() {
                    return null;
                }
            });
        } catch (NacosException e) {
            log.error("load route error: {}", e.getErrMsg());
        }
    }

    public void updateRoute(String content) {
        Yaml yaml = new Yaml();
        GatewayRoute gatewayRoute = yaml.loadAs(content, GatewayRoute.class);
        gatewayRoute.getRoutes().forEach(route -> {
            log.info("load route: {},{}", route.getId(), route);
            this.routeDefinitionWriter.save(Mono.just(route)).subscribe();
        });
    }
}
